const fs = require('fs-extra');
const path = require('path');
const sharp = require('sharp');
const config = require('../config/config');

/**
 * 确保存储目录存在
 * @param {string} userId - 用户ID
 * @param {string} modelId - 模型ID
 * @returns {string} - 存储目录路径
 */
exports.ensureStorageDir = async (userId, modelId) => {
    const storagePath = path.join(config.storage.basePath, userId.toString(), modelId.toString());
    await fs.ensureDir(storagePath);
    return storagePath;
};

/**
 * 确保公共模型存储目录存在
 * @returns {string} - 公共模型存储目录路径
 */
exports.ensurePublicModelStorageDir = async () => {
    const publicStoragePath = path.join(config.storage.basePath, 'public_models');
    await fs.ensureDir(publicStoragePath);
    return publicStoragePath;
};

/**
 * 获取文件扩展名
 * @param {string} filename - 文件名
 * @returns {string} - 文件扩展名 (不带点)
 */
exports.getFileExtension = (filename) => {
    return path.extname(filename).toLowerCase().substring(1);
};

/**
 * 验证文件格式是否合法
 * @param {string} filename - 文件名
 * @returns {boolean} - 是否为合法格式
 */
exports.isValidModelFormat = (filename) => {
    const ext = exports.getFileExtension(filename);
    return config.storage.allowedFormats.includes(ext);
};

/**
 * 删除文件
 * @param {string} filePath - 文件路径
 */
exports.deleteFile = async (filePath) => {
    try {
        if (filePath && await fs.pathExists(filePath)) {
            await fs.unlink(filePath);
        }
    } catch (error) {
        console.error(`删除文件失败: ${filePath}`, error);
    }
};

/**
 * 基于几何体类型生成特定的颜色
 * @param {string} geometryType - 几何体类型
 * @param {string} color - 用户指定的颜色
 * @returns {object} - RGB颜色对象
 */
function getGeometryColor(geometryType, color) {
    // 如果用户指定了颜色，解析它
    if (color && color.startsWith('#') && (color.length === 7 || color.length === 9)) {
        const r = parseInt(color.substring(1, 3), 16);
        const g = parseInt(color.substring(3, 5), 16);
        const b = parseInt(color.substring(5, 7), 16);
        return { r, g, b, alpha: 1 };
    }

    // 否则，为每种几何体类型返回默认颜色
    switch (geometryType) {
        case 'cube':
            return { r: 220, g: 0, b: 0, alpha: 1 }; // 红色
        case 'sphere':
            return { r: 0, g: 100, b: 220, alpha: 1 }; // 蓝色
        case 'cylinder':
            return { r: 0, g: 180, b: 0, alpha: 1 }; // 绿色
        case 'cone':
            return { r: 200, g: 200, b: 0, alpha: 1 }; // 黄色
        case 'torus':
            return { r: 200, g: 0, b: 200, alpha: 1 }; // 紫色
        case 'plane':
            return { r: 150, g: 150, b: 150, alpha: 1 }; // 灰色
        case 'external_model':
            return { r: 50, g: 180, b: 180, alpha: 1 }; // 青色
        default:
            return { r: 100, g: 100, b: 100, alpha: 1 }; // 默认灰色
    }
}

/**
 * 生成几何体缩略图
 * @param {object} geometry - 几何体数据
 * @param {string} outputPath - 输出缩略图路径
 * @returns {string} - 缩略图Base64字符串
 */
exports.generateGeometryThumbnail = async (geometry, outputPath) => {
    const { width, height } = config.storage.thumbnailSize;
    const geometryType = geometry?.type || 'cube';
    const colorStr = geometry?.color || '#FFFFFF';

    // 获取颜色
    const color = getGeometryColor(geometryType, colorStr);

    // 创建一个简单的彩色图像作为几何体缩略图
    await sharp({
        create: {
            width,
            height,
            channels: 4,
            background: color
        }
    })
        .composite([
            {
                input: {
                    text: {
                        text: geometryType.toUpperCase(),
                        font: 'sans-serif',
                        fontSize: 32,
                        align: 'center'
                    }
                },
                gravity: 'center'
            }
        ])
        .png()
        .toFile(outputPath);

    // 将图像转换为Base64
    const thumbnailBuffer = await fs.readFile(outputPath);
    return `data:image/png;base64,${thumbnailBuffer.toString('base64')}`;
};

/**
 * 生成缩略图 (使用模拟方法，实际情况需要使用3D渲染库)
 * @param {string} modelPath - 模型文件路径
 * @param {string} outputPath - 输出缩略图路径
 * @returns {string} - 缩略图Base64字符串
 */
exports.generateThumbnail = async (modelPath, outputPath) => {
    // 注意：这里是模拟生成缩略图，实际应该使用Three.js或其他库渲染3D模型
    // 在实际项目中，这可能需要启动一个无头浏览器或使用专门的渲染服务

    // 创建一个简单的占位图像作为缩略图
    const { width, height } = config.storage.thumbnailSize;
    await sharp({
        create: {
            width,
            height,
            channels: 4,
            background: { r: 100, g: 100, b: 100, alpha: 0.5 }
        }
    })
        .png()
        .toFile(outputPath);

    // 将图像转换为Base64
    const thumbnailBuffer = await fs.readFile(outputPath);
    return `data:image/png;base64,${thumbnailBuffer.toString('base64')}`;
};

/**
 * 导出模型到指定格式
 * @param {object} model - 模型数据
 * @param {string} outputPath - 输出文件路径
 * @param {object} options - 导出选项
 * @returns {object} - 导出结果
 */
exports.exportModel = async (model, outputPath, options) => {
    try {
        // 默认选项
        const exportOptions = {
            format: options.format || 'stl',
            quality: options.quality || 'medium',
            scale: options.scale || 1.0,
            ...options
        };

        // 在此检查模型是否为几何体模型或已上传的模型文件
        if (model.file && model.file.filePath && await fs.pathExists(model.file.filePath)) {
            // 如果是上传的模型文件，处理格式转换
            await handleModelFileExport(model.file.filePath, outputPath, exportOptions);
        } else if (model.geometry) {
            // 如果是几何体模型，生成相应格式的文件
            await handleGeometryExport(model.geometry, outputPath, exportOptions);
        } else {
            return {
                success: false,
                error: '无法导出：模型既没有可用的几何体数据也没有关联的模型文件'
            };
        }

        // 检查导出的文件是否创建成功
        if (await fs.pathExists(outputPath)) {
            return {
                success: true,
                filePath: outputPath,
                format: exportOptions.format
            };
        } else {
            return {
                success: false,
                error: '导出文件创建失败'
            };
        }
    } catch (error) {
        console.error('导出模型错误:', error);
        return {
            success: false,
            error: error.message || '导出过程中发生错误'
        };
    }
};

/**
 * 处理模型文件导出
 * @private
 * @param {string} inputFilePath - 输入文件路径
 * @param {string} outputPath - 输出文件路径
 * @param {object} options - 导出选项
 */
async function handleModelFileExport(inputFilePath, outputPath, options) {
    // 获取输入和输出文件格式
    const inputFormat = path.extname(inputFilePath).toLowerCase().substring(1);
    const outputFormat = options.format.toLowerCase();

    // 如果输入和输出格式相同，直接复制文件
    if (inputFormat === outputFormat) {
        await fs.copy(inputFilePath, outputPath);
        return;
    }

    // 注意：实际项目中，这里应该实现具体的格式转换逻辑
    // 例如，使用外部库或服务进行格式转换
    // 以下是模拟实现

    // 创建一个空文件作为示例
    // 在实际应用中，这里应该使用适当的库或工具进行真实的格式转换
    // 例如 Three.js 的 GLTFExporter, STLExporter 等，或者调用外部命令行工具

    // 模拟文件转换
    await fs.writeFile(outputPath, '模拟导出的模型文件内容');

    console.log(`模拟将模型从 ${inputFormat} 转换为 ${outputFormat} 格式`);
}

/**
 * 处理几何体导出
 * @private
 * @param {object} geometry - 几何体数据
 * @param {string} outputPath - 输出文件路径
 * @param {object} options - 导出选项
 */
async function handleGeometryExport(geometry, outputPath, options) {
    const geometryType = geometry.type;
    const outputFormat = options.format.toLowerCase();

    // 注意：实际项目中，这里应该实现具体的几何体导出逻辑
    // 通常使用Three.js或类似的库生成模型文件
    // 以下是模拟实现

    // 创建一个包含几何体基本信息的示例文件
    let fileContent = '';

    switch (outputFormat) {
        case 'stl':
            fileContent = generateMockSTL(geometry);
            break;
        case 'obj':
            fileContent = generateMockOBJ(geometry);
            break;
        case 'gltf':
        case 'glb':
            fileContent = generateMockGLTF(geometry, outputFormat === 'glb');
            break;
        default:
            throw new Error(`不支持的导出格式: ${outputFormat}`);
    }

    // 写入文件
    await fs.writeFile(outputPath, fileContent);

    console.log(`模拟导出${geometryType}几何体为${outputFormat}格式`);
}

/**
 * 生成模拟的STL文件内容
 * @private
 * @param {object} geometry - 几何体数据
 * @returns {string} - STL文件内容
 */
function generateMockSTL(geometry) {
    return `solid ${geometry.type}
facet normal 0 0 0
    outer loop
        vertex 0 0 0
        vertex 1 0 0
        vertex 0 1 0
    endloop
endfacet
endsolid ${geometry.type}`;
}

/**
 * 生成模拟的OBJ文件内容
 * @private
 * @param {object} geometry - 几何体数据
 * @returns {string} - OBJ文件内容
 */
function generateMockOBJ(geometry) {
    return `# ${geometry.type}
v 0.0 0.0 0.0
v 1.0 0.0 0.0
v 0.0 1.0 0.0
f 1 2 3`;
}

/**
 * 生成模拟的GLTF/GLB文件内容
 * @private
 * @param {object} geometry - 几何体数据
 * @param {boolean} isBinary - 是否为二进制格式(GLB)
 * @returns {string} - GLTF/GLB文件内容
 */
function generateMockGLTF(geometry, isBinary) {
    if (isBinary) {
        // 模拟二进制内容
        return `GLB_BINARY_CONTENT_FOR_${geometry.type}`;
    } else {
        // 模拟JSON内容
        const mockGltf = {
            asset: {
                version: "2.0"
            },
            scene: 0,
            scenes: [
                {
                    nodes: [0]
                }
            ],
            nodes: [
                {
                    mesh: 0,
                    name: geometry.type
                }
            ],
            meshes: [
                {
                    primitives: [
                        {
                            attributes: {
                                POSITION: 0
                            },
                            indices: 1
                        }
                    ]
                }
            ],
            accessors: [
                // 顶点
                {
                    bufferView: 0,
                    componentType: 5126,
                    count: 3,
                    type: "VEC3",
                    max: [1, 1, 1],
                    min: [0, 0, 0]
                },
                // 索引
                {
                    bufferView: 1,
                    componentType: 5123,
                    count: 3,
                    type: "SCALAR"
                }
            ],
            bufferViews: [
                {
                    buffer: 0,
                    byteOffset: 0,
                    byteLength: 36
                },
                {
                    buffer: 0,
                    byteOffset: 36,
                    byteLength: 6
                }
            ],
            buffers: [
                {
                    byteLength: 42,
                    uri: "data:application/octet-stream;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
                }
            ]
        };

        return JSON.stringify(mockGltf, null, 2);
    }
}